package xyz.erupt.flow.bean.entity.node;

import lombok.Data;
import xyz.erupt.flow.constant.FlowConstant;

import java.util.List;

@Data
public class OaProcessNode {

    private String id;

    private String parentId;

    private String desc;

    private String name;

    private String type;

    private OaProcessNodeProps props;

    OaProcessNode children;

    private List<OaProcessNode> branchs;

    /**
     * 根据id查询node
     * @param id
     * @return
     */
    public OaProcessNode findNodeById(String id) {
        if(this.id.equals(id)) return this;
        else{
            if (this.getChildren()!=null && this.getChildren().getId()!=null && !this.getChildren().getId().isEmpty()){
                OaProcessNode node = findSubNodeById(this.getChildren(), id);
                if (node != null) return node;
            }
            if(this.getBranchs()!=null){
                for (OaProcessNode branch : this.getBranchs()) {
                    OaProcessNode node = branch.findSubNodeById(branch, id);
                    if (node != null) return node;
                }
            }

        }
        return null;
    }

    /**
     * 查询子项
     * @param id
     * @return
     */
    private OaProcessNode findSubNodeById(OaProcessNode node,String id) {
        if (node.id.equals(id)) return node;
        else {
            if (node.getChildren()!=null && node.getChildren().getId()!=null && !node.getChildren().getId().isEmpty()){
                OaProcessNode subNodeById = findSubNodeById(node.getChildren(), id);
                if (subNodeById != null) return subNodeById;
            }
            if(node.getBranchs()!=null){
                for (OaProcessNode branch : node.getBranchs()) {
                    OaProcessNode node1 = branch.findSubNodeById(branch, id);
                    if (node1 != null) return node1;
                }
            }
        }
        return null;
    }

    /**
     * 根据id查询上级camunda节点id（连线/节点）（符合bpmn设计流程思路）
     * @param id 本级节点id（workFlow）
     * @return
     */
    public String findSuperNodeById(String id) {
        OaProcessNode node = findNodeById(id);//查询出当前节点
        //判断该子节点是否拥有父级节点
        if (node.getParentId()!=null && !node.getParentId().isEmpty()){
            String parentId = node.getParentId();
            OaProcessNode parentNode = findNodeById(parentId);//查找父级id
            if(checkBranch(parentNode)){//上级为分支父节点情况
                return parentNode.getParentId();//重新执行其所有分支节点
            }else if(checkBranchNode(parentNode)){//上级为分支子节点情况
                //将该分支和其他分支结束，回到上级节点中
                OaProcessNode node1 = findNodeById(parentNode.getParentId());//分支父节点
                OaProcessNode node2 = findNodeById(node1.getParentId());//分支父节点的上级节点
                if(FlowConstant.NODE_TYPE_ROOT_VALUE.equals(node2.getId())){//该节点为发起人节点
                    return node2.getId();
                }
                return toMultiNodeId(node2.getId());
            }else {//其他情况
                if (parentNode.getParentId() == null || parentNode.getParentId().isEmpty()) {//上级节点为发起人情况
                    return parentId;//返回发起人开始
                }
                else {
                    return toMultiNodeId(parentId);
                }
            }
        }else {//无父级id则表示为根节点（返回null）
            return null;
        }
    }

    /**
     * 跳转任意节点，获取camunda节点id(连线/节点)(符合bpmn设计流程思路)
     * @param id 跳转节点的id（workFlow）
     * @return
     */
    public String gotoNodeById(String id) {
        OaProcessNode node = findNodeById(id);//获取跳转节点
        String parentId = node.getParentId();
        if(parentId!=null && !parentId.isEmpty()){
           return toMultiNodeId(id);
        }else {//跳转节点为根节点（发起人）
            return id;//直接返回
        }
    }

    /**
     * 为节点添加多实例后缀
     * @param id
     * @return
     */
    public static String toMultiNodeId(String id){
        String multi = "#multiInstanceBody";//多实例节点后缀（除发起人节点外均为多实例节点）
        return id+multi;
    }

    /**
     * 判断是否为分支节点
     * @param parentNode
     * @return
     */
    private boolean checkBranchNode(OaProcessNode parentNode) {
        return parentNode.getType().equals(FlowConstant.NODE_TYPE_CONDITION)||parentNode.getType().equals(FlowConstant.NODE_TYPE_CONCURRENT);
    }

    /**
     * 判断是否为分支父级节点
     * @param parentNode
     * @return
     */
    private boolean checkBranch(OaProcessNode parentNode) {
        return parentNode.getType().equals(FlowConstant.NODE_TYPE_EMPTY);
    }

    //新增监听器
    private OaProcessRootNodeMonitor monitors;
}
